import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { Observable, throwError } from 'rxjs'
import { catchError, map } from 'rxjs/operators'

import { RoleService } from './role.service'
import { preProcessParams, encodeParams } from '@shared/decorators'
import { generateOptions } from 'app/utils/helpers'
import { COMB_URL } from 'app/utils/contraints'
import { DataService } from '@shared/services/data.service'
import { IUserPagination } from '@shared/interfaces/user'
import { IQueryParams } from '@shared/interfaces/queryParams'
import { IRoleQueryParams, IRolePagination, Role, IRoleUpdate, IMenu } from '@shared/interfaces/role'

@Injectable()
export class RoleAlinterService implements RoleService {
  constructor(
    public dataService: DataService,
    private http: HttpClient,
  ) { }

  @preProcessParams()
  public getList(params: IRoleQueryParams): Observable<IRolePagination> {
    const options = generateOptions(params)
    const url = `${COMB_URL}/camel/roles`
    return this.http.get<IRolePagination>(url, options)
  }

  public getRoleById(roleId: number): Observable<Role> {
    const url = `${COMB_URL}/camel/role/${roleId}`
    return this.http.get<Role>(url)
  }

  @preProcessParams()
  @encodeParams()
  public getUsersOfOneRole(params: IQueryParams, roleId: number, str?: string): Observable<IUserPagination> {
    const url = `${COMB_URL}/camel/role/${roleId}/users?${str}`
    return this.http.get<IUserPagination>(url)
  }

  public updateRole(roleId: number, data: IRoleUpdate): Observable<Role> {
    const url = `${COMB_URL}/camel/role/${roleId}`
    return this.http.put<Role>(url, data)
  }

  createRole(role: IRoleUpdate): Observable<boolean> {
    const url = `${COMB_URL}/camel/role`

    return this.http
      .post(url, role, {
        responseType: 'text',
        observe: 'response',
      })
      .pipe(
        map(resp => {
          const { status } = resp
          if (status === 201) {
            return true
          }

          throwError(resp)
        }),
        catchError(error => {
          return throwError(error)
        }),
      )
  }

  getMenus(): Observable<IMenu[]> {
    const url = `${COMB_URL}/camel/menus`
    return this.http.get<IMenu[]>(url, {})
  }

  deleteRole(roleId: string): Observable<boolean> {
    const url = `${COMB_URL}/camel/role/${roleId}`
    return this.http.delete<boolean>(url).pipe(
      map(
        res => true,
        catchError(err => throwError(err))
      )
    )
  }

  updateMenusOfRole(roleId: number, menus: number[]): Observable<boolean> {
    const url = `${COMB_URL}/camel/role/${roleId}/menus`
    return this.http.put(url, {menus}, {
      responseType: 'text',
      observe: 'response',
    })
    .pipe(
      map(resp => {
        const { status } = resp
        if (status === 200) {
          return true
        }

        throwError(resp)
      }),
      catchError(error => {
        return throwError(error)
      }),
    )
  }

  /** 冻结 */
  freeze(roleId: number): Observable<boolean> {
    const url = `${COMB_URL}/camel/role/${roleId}/freeze`
    return this.http.put<boolean>(url, {})
  }

  /** 解冻 */
  unfreeze(roleId: number): Observable<boolean> {
    const url = `${COMB_URL}/camel/role/${roleId}/unfreeze`
    return this.http.put<boolean>(url, {})
  }
}
